package com.yaolonga.itfc.manager.core;


import cn.hutool.core.io.resource.Resource;
import cn.hutool.core.lang.Filter;
import com.yaolonga.itfc.manager.core.utils.StreamUtils;

import java.io.InputStream;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.Function;

/**
 * @Author: yaolong
 * @CreateTime: 2024-10-17  10:24
 * @Description: TODO
 * @Version: 1.0
 */
public class NetworkInterfaceHelper {


    /**
     * 根据IP地址获取对应的网卡信息
     * @param ipAddress
     * @return
     */
    public static NetworkInterface getNetworkInterface(String ipAddress) {
        Enumeration<NetworkInterface> networkInterfaces;
        try {
            networkInterfaces = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }

        if (networkInterfaces == null) {
            throw new RuntimeException("Get network interface error!");
        }
        while (networkInterfaces.hasMoreElements()) {
            final NetworkInterface networkInterface = networkInterfaces.nextElement();
            final Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
            while (inetAddresses.hasMoreElements()) {
                final InetAddress inetAddress = inetAddresses.nextElement();
                if (inetAddress instanceof Inet4Address && ipAddress.equals(inetAddress.getHostAddress())){
                    return networkInterface;
                }
            }
        }
        return null;
    }


    public static String getResource(Callable<Resource> resource) {
        try {
            Resource r = resource.call();
            try (InputStream input = r.getStream()) {
                return StreamUtils.copyToString(input, StandardCharsets.UTF_8);
            }
        } catch (Throwable ignore) {

        }
        return "";
    }

    /**
     * 获取网卡IPv4地址映射表
     * @return 网卡IPv4地址映射表
     */
    public static Map<NetworkInterface, LinkedHashSet<InetAddress>> getNicIpV4Map() {
        return getNicIpV4Map(true);
    }

    /**
     * 获取网卡IPv4地址映射表
     * @return 网卡IPv4地址映射表
     */
    public static Map<NetworkInterface, LinkedHashSet<InetAddress>> getNicIpV4Map(boolean excludeVirtual) {
        return getNicAdreesMap(
                networkInterface -> !excludeVirtual || !networkInterface.isVirtual(),
                inetAddress -> inetAddress instanceof Inet4Address
        );
    }




    public static Map<NetworkInterface, LinkedHashSet<InetAddress>> getNicAdreesMap(Filter<InetAddress> addressFilter) {
        return getNicAdreesMap(null, addressFilter);
    }

    /**
     * 获取网卡地址映射
     *
     * @param networkInterfaceFilter 网桥过滤器
     * @param addressFilter          地址过滤器
     * @return 映射表
     */
    public static Map<NetworkInterface, LinkedHashSet<InetAddress>> getNicAdreesMap(Filter<NetworkInterface> networkInterfaceFilter, Filter<InetAddress> addressFilter) {
        Enumeration<NetworkInterface> networkInterfaces;
        try {
            networkInterfaces = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }

        if (networkInterfaces == null) {
            throw new RuntimeException("Get network interface error!");
        }

        Map<NetworkInterface, LinkedHashSet<InetAddress>> nicIpMap = new HashMap<>();


        while (networkInterfaces.hasMoreElements()) {
            final NetworkInterface networkInterface = networkInterfaces.nextElement();
            if (networkInterfaceFilter != null && !networkInterfaceFilter.accept(networkInterface)) {
                continue;
            }
            final Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
            while (inetAddresses.hasMoreElements()) {
                final InetAddress inetAddress = inetAddresses.nextElement();
                if (inetAddress != null && (null == addressFilter || addressFilter.accept(inetAddress))) {
                    LinkedHashSet<InetAddress> ipSet = nicIpMap.computeIfAbsent(networkInterface, k -> new LinkedHashSet<>());
                    ipSet.add(inetAddress);
                }
            }
        }
        return nicIpMap;
    }
}
